const fcl =  require("@onflow/fcl");
const sdk =  require("@onflow/sdk");
const  t = require("@onflow/types");
const EC = require("elliptic").ec;
const fs = require("fs");
const path = require("path");
const SHA3 = require("sha3").SHA3;
const ec = new EC("p256");
const config = require('../config');
const minterFlowAddress = config.minterAddress
const minterPrivateKeyHex = config.minterPrivateKeyHex
const minterAccountIndex = config.minterAccountKeyIndex
const nonFungibleTokenAddress = config.nonFungibleTokenAddress
const NftEggsNFTPath = "../contracts/NftEggsNFT.cdc"
const NftEggsStorePath = "../contracts/NftEggsStore.cdc"
const NonFungibleTokenPath = "../contracts/NonFungibleToken.cdc"

fcl.config()
    .put("env", "local")
    .put("accessNode.api", "http://172.25.144.8:8080")
    .put("discovery.wallet", "http://172.25.144.8:3000/fcl/authn")
    .put("challenge.handshake", "http://172.25.144.8:3000/fcl/authn")
  // .put("env", "testnet")
  // .put("accessNode.api", "https://access-testnet.onflow.org")
  // .put("discovery.wallet", "https://fcl-discovery.onflow.org/testnet/authn") 
  // .put("env", "mainnet")
  // .put("accessNode.api", "https://access-mainnet-beta.onflow.org")
  // .put("discovery.wallet", "https://fcl-discovery.onflow.org/authn")
  // .put("env", config.env)
  // .put("accessNode.api", config.accessApi)
  // .put("discovery.wallet", config.discoveryApi)  

const authorizeMinter = async (account) => {
	  const user = await getAccount(minterFlowAddress);
      const key = user.keys[minterAccountIndex];
	  console.log(Number(key.index))
      return {
        ...account,
        tempId: `${user.address}-${key.index}`,
        addr: fcl.sansPrefix(user.address),
        keyId: Number(key.index),
        signingFunction: (signable) => {
			console.log('signable',signable)
			return {
				addr: fcl.withPrefix(user.address),
				keyId: Number(key.index),
				signature: signWithKey(minterPrivateKeyHex,  signable.message),
			}
		},
      };
    };

	
const setupAccount = async () => {
    const authorization = authorizeMinter();
    const transaction = fs.readFileSync(
        path.join(__dirname,`../cadence/transactions/setup_account.cdc`),
        "utf8"
    )
    .replace(NftEggsNFTPath, fcl.withPrefix(minterFlowAddress))
    .replace(NftEggsStorePath, fcl.withPrefix(minterFlowAddress));

    return sendTx({
		transaction,
		args: [],
		authorizations: [authorization],
		payer: authorization,
		proposer: authorization,
    });
};  

const getAccount = async (addr) => {
    const { account } = await fcl.send([fcl.getAccount(addr)]);
    return account;
  };

const signWithKey = (privateKey, msg) => {
    console.log('signWithKey')
    console.log(msg)
	const key = ec.keyFromPrivate(Buffer.from(privateKey, "hex"));
    const sig = key.sign(hashMsg(msg));
    const n = 32;
    const r = sig.r.toArrayLike(Buffer, "be", n);
    const s = sig.s.toArrayLike(Buffer, "be", n);
    return Buffer.concat([r, s]).toString("hex");
  };

const hashMsg = (msg) => {
    const sha = new SHA3(256);
    sha.update(Buffer.from(msg, "hex"));
    return sha.digest();
  };

const sendTx = async ({
    transaction,
    args,
    proposer,
    authorizations,
    payer,
}) => {
	console.log('proposer',proposer)
	console.log('payer',payer)
	console.log('authorizations',authorizations)
    const response = await fcl.send([
		fcl.transaction`
			${transaction}
		`,
		fcl.args(args),
		fcl.proposer(proposer),
		fcl.authorizations(authorizations),
		fcl.payer(payer),
		fcl.limit(9999),
    ]);
	console.log('response',fcl.tx(response).onceSealed())
	const res = await fcl.tx(response).onceSealed();
	console.log('response',res)
	return res
    //return await fcl.tx(response).onceSealed();
};

const executeScript = async ( script, args ) => {
    const response = await fcl.send([fcl.script`${script}`, fcl.args(args)]);
    return await fcl.decode(response);
  }

const getLatestBlockHeight = async () => {
    const block = await fcl.send([fcl.getBlock(true)]);
    const decoded = await fcl.decode(block);
    return decoded.height;
  }
  
const getTransaction = async (tx_id) => {
    const transaction = await fcl.send([fcl.getTransaction(tx_id)]);
    return await fcl.decode(transaction);
}


const mint = async (recipient, setId, itemId, creator, title, asset, serial) => {
    const authorization = authorizeMinter();

    const transaction = fs.readFileSync(
        path.join(__dirname,`../cadence/transactions/mint_nft.cdc`),
        "utf8"
    )
    .replace(NftEggsNFTPath, fcl.withPrefix(minterFlowAddress))
    .replace(NonFungibleTokenPath, fcl.withPrefix(nonFungibleTokenAddress));

    return sendTx({
		transaction,
		args: [fcl.arg(recipient, t.Address), fcl.arg(setId, t.String), fcl.arg(itemId, t.String), fcl.arg(creator, t.String), fcl.arg(title, t.String), fcl.arg(asset, t.String), fcl.arg(serial, t.String)],
		authorizations: [authorization],
		payer: authorization,
		proposer: authorization,
    });
};

module.exports = {
	setupAccount: setupAccount,
    getLatestBlockHeight: getLatestBlockHeight,
    getTransaction: getTransaction,
	getAccount: getAccount,
	authorizeMinter: authorizeMinter,
	executeScript: executeScript,
	sendTx: sendTx,
	mint: mint
}
